package main

import "fmt"

// for循环实现阶乘
func facv1(n int) int {
	if n == 0 {
		return 1
	} else if n < 0 {
		panic("不支持负数")
	}
	fact := 1
	for i := 1; i <= n; i++ {
		fact = fact * i
	}
	return fact
}

// 对for循环改变为递归实现阶乘
// 参数a需为固定的1值，即阶乘最小正整数
func facv2(a, n int) int {
	if n == 0 {
		return a
	} else if n < 0 {
		panic("不支持负数")
	}
	a = a * n
	n--
	return facv2(a, n)
}

// 利用公式递推为函数
func facv3(n int) int {
	if n == 0 {
		return 1
	} else if n < 0 {
		panic("不支持负数")
	}
	return facv3(n-1) * n
}

// 对facv3函数利用hash表进行优化
func facv31(n int, m map[int]int) int {
	if n == 0 {
		return 1
	} else if n < 0 {
		panic("不支持负数")
	}
	v, ok := m[n]
	if ok {
		return v
	} else {
		v = facv31(n-1, m) * n
		m[n] = v
		return v
	}
}

// 对facv3函数利用切片进行优化
func facv32(n int, s []int) int {
	if n == 0 {
		return 1
	} else if n < 0 {
		panic("不支持负数")
	}
	if s[n] == 0 {
		s[n] = facv3(n-1) * n
	}
	return s[n]
}

// 倒三角函数
func trig(n int) {
	if n <= 0 {
		panic("不支持负数")
	}
	wid := 0
	if n > 9 {
		wid = n - 9
	}
	for i := 1; i <= n; i++ {
		if i < 10 {

			fmt.Printf("%-[2]*[1]v", "", (n-i)*2+wid)
		} else {

			fmt.Printf("%-[2]*[1]v", "", (n-i)*2+(n-i))
		}
		for k := i; k > 0; k-- {
			fmt.Printf("%v ", k)
		}
		fmt.Println()
	}
}

// 倒三角递归实现
func trigv1(n, wid int) int {
	if n <= 0 {
		panic("不支持负数")
	}
	if n == 1 {
		if wid < 10 {
			wid = wid*2 - 2
		} else {
			wid = (wid-1)*2 + (wid - 9)
		}
		fmt.Printf("%-[2]*[1]v%[3]d\n", "", wid, 1)
		return wid
	}
	if n < 10 {
		wid = trigv1(n-1, wid) - 2
		fmt.Printf("%-[2]*[1]v", "", wid)
	} else {
		wid = trigv1(n-1, wid) - 3
		fmt.Printf("%-[2]*[1]v", "", wid)
	}
	for i := n; i > 0; i-- {
		fmt.Printf("%v ", i)
	}
	fmt.Println()
	return wid
}

func main() {
	// 求阶乘
	num := 10
	m0 := make(map[int]int, num)
	s0 := make([]int, num+1)
	fmt.Printf("facv1函数结果:%d\n", facv1(num))
	fmt.Printf("facv2函数结果:%d\n", facv2(1, num))
	fmt.Printf("facv3函数结果:%v\n", facv3(num))
	fmt.Printf("facv31函数结果:%d\n", facv31(num, m0))
	fmt.Printf("facv32函数结果:%d\n", facv32(num, s0))

	// 倒三角打印
	numb := 22
	trig(numb)
	trigv1(numb, numb)
}

// 批改意见
// 1. 几种实现方法都很不错，对异常的处理也非常到位